#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sublime
import os
import re
import codecs
import threading
from . import LuaCommon
from .. import Common

FILE_EXT = '.lua'
snippetTemplate = '''<snippet>
	<content><![CDATA[$content]]></content>
	<tabTrigger>$trigger</tabTrigger>
	<scope>source%s</scope>
	<description>$desc</description>
</snippet>
''' % FILE_EXT

def buildDir(dirs):
	if len(dirs) == 0:
		dirs = sublime.active_window().folders()

	if len(dirs) == 0:
		return
	
	if LuaCommon.checkWorkState():
		return

	LuaCommon.setWorkState(True)
	threading.Thread(target=buildDirAsync, args=(dirs,)).start()

def buildDirAsync(dirs):
	definitionsList = LuaCommon.getUserDefinitionsList()
	cachepath = LuaCommon.getUserCachePath()
	Common.makedirs(cachepath)
	for path in dirs:
		for i in range(len(definitionsList), 0, -1):
			if definitionsList[i - 1][2].find(path) >= 0:
				del definitionsList[i - 1]

		workpath = os.path.join(cachepath, path.replace(':', ''))
		Common.cleanPath(workpath)
		snippetDir(path, workpath)

	saveUserDefinitions()
	sublime.message_dialog('build folder definition complete!')

def buildFile(filepath):
	if not filepath:
		return

	if not Common.checkExtName(filepath, FILE_EXT):
		return
	
	if LuaCommon.checkWorkState(False):
		return

	LuaCommon.setWorkState(True)
	threading.Thread(target=buildFileAsync, args=(filepath,)).start()

def buildFileAsync(path):
	definitionsList = LuaCommon.getUserDefinitionsList()
	cachepath = LuaCommon.getUserCachePath()
	for i in range(len(definitionsList), 0, -1):
		if definitionsList[i - 1][2].find(path) >= 0:
			del definitionsList[i - 1]

	workpath = os.path.join(cachepath, path.replace(':', ''))
	workpath = Common.getNoExtName(workpath)
	Common.cleanPath(workpath)
	snippetFile(path, workpath)

	saveUserDefinitions()
	sublime.status_message('build file definition complete!')

def saveUserDefinitions():
	LuaCommon.setWorkState(False)
	Common.writeJson(LuaCommon.getUserConfigPath(), LuaCommon.getUserDefinitionsList())

def snippetDir(source, target):
	for path in os.listdir(source):
		sourcePath = os.path.join(source, path)
		targetPath = os.path.join(target, path)
		if os.path.islink(sourcePath):
			continue
		elif os.path.isdir(sourcePath):
			snippetDir(sourcePath, targetPath)
		elif os.path.isfile(sourcePath) and Common.checkExtName(sourcePath, FILE_EXT):
			snippetFile(sourcePath, Common.getNoExtName(targetPath))

def snippetFile(filepath, savepath):
	Common.makedirs(savepath)

	snippetList = []
	with codecs.open(filepath, 'r', 'utf-8') as f:
		linenum = 0
		for line in f.readlines():
			linenum += 1
			# class
			m = re.match('^local\s+(\w+)\s*=\s*\{\}', line)
			if m:
				snippetList.append(m.group(1))
				handleDefinition(m.group(1), None, filepath, linenum)
				continue

			m = re.match('^local\s+(\w+)\s*=\s*class\(', line)
			if m:
				snippetList.append(m.group(1))
				handleDefinition(m.group(1), None, filepath, linenum)
				continue
			
			m = re.match('^(\w+)\s*=\s*class\(', line)
			if m:
				snippetList.append(m.group(1))
				handleDefinition(m.group(1), None, filepath, linenum)
				continue

			# function
			m = re.match('^function\s+(\w+\.*\w*)\s*\((.*)\)', line)
			if m:
				saveSnippet(savepath, '', m.group(1), m.group(2))
				handleDefinition(m.group(1), m.group(2), filepath, linenum)
				continue
			
			# class function
			m = re.match('^function\s+(\w+)\:(\w+)\s*\((.*)\)', line)
			if m:
				method = m.group(2)
				if method == 'ctor':
					continue
				saveSnippet(savepath, m.group(1), method, m.group(3))
				handleDefinition(m.group(2), m.group(3), filepath, linenum, m.group(1) + ':' + m.group(2))
				continue
			
			# local property
			m = re.match('^\s*local\s+(\w+)\s*', line)
			if m:
				snippetList.append(m.group(1))
				continue
			
			m = re.match('^\s*(self\.\w+)\s*=', line)
			if m:
				snippetList.append(m.group(1))
				continue

			# global property
			m = re.match('^(\w+\.?\w*)\s*=', line)
			if m:
				snippetList.append(m.group(1))
				handleDefinition(m.group(1), None, filepath, linenum)
				continue
	
	saveSnippetList(savepath, snippetList)

def handleDefinition(funcname, params, filepath, linenum, function=None):
	if function == None:
		function = funcname
	if params:
		function += '(%s)' % getParamList(params)[0]

	funclist = []
	pos = funcname.find('.')
	if pos < -1:
		pos = funcname.find(':')
	if pos >= 0:
		funclist.append(funcname[pos + 1:])
	funclist.append(funcname)

	LuaCommon.getUserDefinitionsList().append([funclist, function, filepath, linenum, 0])

def getParamList(params):
	paramlist1 = []
	for param in params.split(','):
		param = re.sub('\s', '', param)
		if param != '' and param != 'void':
			paramlist1.append(param)
	
	paramlist2 = []
	for i in range(0, len(paramlist1)):
		paramlist2.append('${%d:%s}' % (i + 1, paramlist1[i]))

	return [', '.join(paramlist1), ', '.join(paramlist2)]

def saveSnippet(savepath, classname, funcname, params): 
	paramlist = getParamList(params)
	if paramlist[0] != '':
		params = paramlist[0].split(',')
		for i in range(0, len(params)):
			params[i] = re.sub('\W', '', params[i])
		string = '-%s' % '-'.join(params)
	else:
		string = ''
	filepath = '%s%s.sublime-snippet' % (funcname, string)
	filepath = os.path.join(savepath, filepath)

	trigger = '%s(%s)' % (funcname, paramlist[0])
	content = '%s(%s)' % (funcname, paramlist[1])
	snippet = snippetTemplate.replace('$content', content).replace('$trigger', trigger).replace('$desc', classname)

	Common.writeFile(filepath, snippet)

def saveSnippetList(savepath, snippetList):
	if len(snippetList) == 0:
		return

	snippetList = sorted(set(snippetList), key = snippetList.index)
	for item in snippetList:
		filepath = re.sub('\W', '_', item) + '.sublime-snippet'
		filepath = os.path.join(savepath, filepath)

		snippet = snippetTemplate.replace('$content', item).replace('$trigger', item).replace('$desc', '.')

		Common.writeFile(filepath, snippet)
